package deepr.lib;

import deepr.core.*;
import deepr.entity.DeeprRequest;
import deepr.filter.FilterParser;
import deepr.src.DeeprUser;
import deepr.src.ParseResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.buf.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.util.HashMap;

@Slf4j
public class PgQlLib {

  //      WITH task_res AS(
//      	SELECT id,asset_category_id,spec FROM crsw.asset
//      ),
//      task_count_res AS(
//      	SELECT count(*) AS total_count FROM task_res
//      ),
//      page_res AS(
//      	SELECT * FROM task_res LIMIT 50 OFFSET 0
//      ),
//      category_res AS(
//      	select page_res.id, page_res.asset_category_id, page_res.spec, category_id  FROM  page_res inner join crsw.asset_category ac on ac.id = page_res.asset_category_id
//      )
//      SELECT 'user','list',1 as page,
//      (SELECT (total_count + 20 - 1)/20 FROM task_count_res),
//      (SELECT array_to_json(array_agg(row_to_json(t))) FROM category_res t)
  public static String list(DisposeContext ctx, DeeprRequest deeprRequest) throws Exception {
    HashMap<String, Object>[] filter = deeprRequest.getFilter();
    FilterParser filterParser = new FilterParser(ctx);
    String object = deeprRequest.getObject();
    StringBuilder filterStr = filterParser.parse(object, filter);
    String[] select = deeprRequest.getSelect();
    Integer page = deeprRequest.getPage();
    SchemaData schemaData = SchemaManager.getSchemaData(object);

    HashMap<String, PropertyData> fields = schemaData.getFields();
    StringBuilder sb = new StringBuilder();
    String table = schemaData.getName();
    String tableRes = table + "_res";
    String countRes = table + "_count_res";
    String pageRes = table + "_page_res";
    int pageSize = 20;
    sb.append("WITH ");
    sb.append(tableRes).append(" AS(\n");
    sb.append("\tSELECT ").append(parseSelectKeys(ctx, fields, object, select)).append(" FROM ").append(getTableName(ctx, table)).append(filterStr).append("\n");
    sb.append("),\n");
    sb.append(countRes).append(" AS(\n");
    sb.append("\tSELECT count(*) AS total_count FROM ").append(tableRes).append("\n),\n");
    sb.append(pageRes).append(" AS(\n");
    sb.append("\tSELECT * FROM ").append(tableRes).append(getPaginateStr(pageSize, page)).append("\n");
    sb.append(")\n");
    sb.append("SELECT '").append(object).append("', 'list',").append(page).append(" AS page,\n");
    sb.append("(SELECT * FROM ").append(countRes).append(") AS totalCount,\n");
    sb.append("(SELECT (total_count + ").append(pageSize - 1).append(" / ").append(pageSize).append(") FROM ").append(countRes).append(") as totalPage,\n");
    sb.append("(SELECT array_to_json(array_agg(row_to_json(t))) FROM (SELECT * FROM ").append(pageRes).append(")) as list\n");
    return sb.toString();
  }


  public static String info(DisposeContext ctx, DeeprRequest deeprRequest) throws Exception {
    HashMap<String, Object>[] filter = deeprRequest.getFilter();
    FilterParser filterParser = new FilterParser(ctx);
    String object = deeprRequest.getObject();
    StringBuilder filterStr = filterParser.parse(object, filter);
    String[] select = deeprRequest.getSelect();
    SchemaData schemaData = SchemaManager.getSchemaData(object);

    HashMap<String, PropertyData> fields = schemaData.getFields();
    StringBuilder sb = new StringBuilder();
    String table = schemaData.getName();
    sb.append("SELECT ").append(parseSelectKeys(ctx, fields, object, select)).append(" FROM ").
        append(getTableName(ctx, table)).append(filterStr).append(" limit 1");
    return sb.toString();
  }

  public static String getTableName(DisposeContext ctx, String table) {
    return table;
  }

  public static String getPaginateStr(int pageSize, int page) {
    return " LIMIT " + pageSize + " OFFSET " + (page - 1) * pageSize;
  }

  public static String getFilterStr(ParseResult parseResult, String object) {
    String filterStr = parseResult.getPgFilter().get(object);
    if (filterStr == null)
      filterStr = "";
    else
      filterStr = " WHERE " + filterStr;
    return filterStr;
  }


  public static String parseSelectKeys(DisposeContext ctx, HashMap<String, PropertyData> fields, String object, String[] select) throws Exception {
    StringBuilder sb = new StringBuilder();
    for (String s : select) {
      if (sb.length() > 0)
        sb.append(",");
      PropertyData propertyData = fields.get(s);
      log.debug("object: {}, field: {}, fieldInfo: {}", object, s, propertyData);
      if (propertyData != null) {
        Class<?> handler = propertyData.getHandler();
        if (handler != null) {
          sb.append(
              handler.getMethod("select",
                  DisposeContext.class, String.class, String.class, Object.class).
                  invoke(handler.newInstance(), ctx, object, s, propertyData.getHandlerArgs()));
        } else
          sb.append(s);
      } else {
        sb.append(s);
      }
    }
    return sb.toString();
  }

}
